package com.qiyi.player.core.video.file.actors.datatile
{
   import com.qiyi.player.core.model.impls.Segment;
   import com.qiyi.player.core.model.impls.Keyframe;
   import com.qiyi.player.base.flv.FLVParser;
   import com.qiyi.player.base.pub.EnumItem;
   import com.qiyi.player.base.flv.FLVTagScriptDataObject;
   import com.qiyi.player.base.flv.FLVTag;
   import com.qiyi.player.core.player.coreplayer.ICorePlayer;
   import com.qiyi.player.base.flv.FLVTagAudio;
   import com.qiyi.player.base.flv.FLVTagVideo;
   import com.qiyi.player.core.player.def.PlayerUseTypeEnum;
   import com.qiyi.player.core.model.def.PlayerTypeEnum;
   import com.qiyi.player.core.Config;
   import flash.utils.ByteArray;
   import flash.utils.IDataInput;
   import com.qiyi.player.core.video.def.DataSourceTypeEnum;
   import flash.utils.getTimer;
   
   public class FlvBlock extends Block implements IFlvBlock
   {
      
      public function FlvBlock(param1:Segment, param2:Keyframe, param3:ICorePlayer, param4:Boolean = false) {
         super();
         this._id = getTimer();
         this._segment = param1;
         this._startKeyframe = param2;
         this._holder = param3;
         if(this._segment.keyframeInited)
         {
            this._timestampAdjustJudged = true;
            this._timestampNeedAdjust = !this._segment.keyframeAdjusted;
         }
         this._limitUniqueSource = param4;
         this._referTimestamp = this._segment.startTime;
         this._videoTags = new Vector.<TagInfo>();
      }
      
      private const SIZE_LIMIT:int = 1.048576E8;
      
      private var _id:int = -1;
      
      private var _segment:Segment;
      
      private var _startKeyframe:Keyframe;
      
      private var _referTimestamp:int = 0;
      
      private var _duration:int = 0;
      
      private var _hasMetaData:Boolean = false;
      
      private var _eof:Boolean = false;
      
      private var _endOfFile:Boolean = false;
      
      private var _complete:Boolean = false;
      
      private var _discard:Boolean = true;
      
      private var _limitUniqueSource:Boolean = false;
      
      private var _loading:Boolean = false;
      
      private var _parser:FLVParser;
      
      private var _videoTags:Vector.<TagInfo>;
      
      private var _expectEndPosition:int = 0;
      
      private var _startTime:int = -1;
      
      private var _endTime:int = 0;
      
      private var _lastReadPosition:uint = 0;
      
      private var _lastReadTagIndex:int = 0;
      
      private var _dataSourceType:EnumItem;
      
      private var _metadata:FLVTagScriptDataObject = null;
      
      private var _configVideoTag:FLVTag = null;
      
      private var _configAudioTag:FLVTag = null;
      
      private var _timestampAdjustJudged:Boolean = false;
      
      private var _timestampNeedAdjust:Boolean = false;
      
      private var _holder:ICorePlayer;
      
      public function get id() : int {
         return this._id;
      }
      
      public function get segment() : Segment {
         return this._segment;
      }
      
      public function get startKeyframe() : Keyframe {
         return this._startKeyframe;
      }
      
      public function get endOfFile() : Boolean {
         return this._endOfFile;
      }
      
      public function set endOfFile(param1:Boolean) : void {
         this._endOfFile = param1;
      }
      
      override public function get startPosition() : int {
         if((this._startKeyframe) && (!(this._startKeyframe.index == 0)) && !this._hasMetaData)
         {
            return this._startKeyframe.position;
         }
         return 0;
      }
      
      override public function get endPosition() : int {
         var _loc1_:int = this.startPosition;
         return _loc1_ == 0?_bytes.length:_loc1_ + this.mediaSize;
      }
      
      public function get startTime() : int {
         if(this._startTime == -1)
         {
            if(this._startKeyframe)
            {
               return this._startKeyframe.time;
            }
            return this._segment.startTime;
         }
         return this._startTime;
      }
      
      public function get endTime() : int {
         return this._endTime == 0?this.startTime:this._endTime;
      }
      
      public function get expectEndPosition() : int {
         return this._expectEndPosition;
      }
      
      public function set expectEndPosition(param1:int) : void {
         this._expectEndPosition = param1;
      }
      
      public function get eof() : Boolean {
         return this._eof;
      }
      
      public function get appending() : Boolean {
         return !(this._parser == null);
      }
      
      public function get discard() : Boolean {
         return this._discard;
      }
      
      public function get duration() : int {
         return this._duration;
      }
      
      public function get mediaSize() : int {
         if(this._videoTags.length == 0)
         {
            return 0;
         }
         return _bytes.length - this._videoTags[0].position;
      }
      
      public function get complete() : Boolean {
         return this._complete;
      }
      
      public function set complete(param1:Boolean) : void {
         this._complete = param1;
      }
      
      public function get configAudioTag() : FLVTagAudio {
         return this._configAudioTag as FLVTagAudio;
      }
      
      public function get configVideoTag() : FLVTagVideo {
         return this._configVideoTag as FLVTagVideo;
      }
      
      public function get loading() : Boolean {
         return this._loading;
      }
      
      public function set loading(param1:Boolean) : void {
         this._loading = param1;
      }
      
      public function get dataSourceType() : EnumItem {
         return this._dataSourceType;
      }
      
      public function set dataSourceType(param1:EnumItem) : void {
         this._dataSourceType = param1;
      }
      
      public function get limitUniqueSource() : Boolean {
         return this._limitUniqueSource;
      }
      
      public function reset() : void {
         this._eof = false;
         this._lastReadPosition = (this._videoTags) && this._videoTags.length > 0?this._videoTags[0].position:0;
         this._lastReadTagIndex = 0;
      }
      
      public function seek(param1:int) : int {
         if((this.discard) || param1 < this._videoTags[0].time || param1 > this._videoTags[this._videoTags.length - 1].time)
         {
            return -1;
         }
         var _loc2_:* = -1;
         var _loc3_:* = 0;
         var _loc4_:int = this._videoTags.length;
         while(_loc3_ < _loc4_)
         {
            if(this._videoTags[_loc3_].time == param1)
            {
               _loc2_ = _loc3_;
               break;
            }
            if(this._videoTags[_loc3_].time > param1)
            {
               _loc2_ = _loc3_;
               if(this._videoTags[_loc3_].time - param1 > param1 - this._videoTags[_loc3_ - 1].time)
               {
                  _loc2_ = _loc3_ - 1;
               }
               break;
            }
            _loc3_++;
         }
         if(_loc2_ >= 0)
         {
            this._lastReadTagIndex = _loc2_;
            this._lastReadPosition = this._videoTags[_loc2_].position;
            this._eof = false;
            return this._videoTags[_loc2_].time;
         }
         return -1;
      }
      
      public function read() : MediaData {
         return this.readData(-1);
      }
      
      private function readData(param1:int) : MediaData {
         var _loc10_:* = 0;
         if(this._discard)
         {
            return null;
         }
         if(param1 == -1 && this._lastReadPosition == _bytes.length)
         {
            return null;
         }
         var _loc2_:MediaData = new MediaData();
         var _loc3_:int = param1 == -1?this._lastReadTagIndex:param1;
         var _loc4_:int = param1 >= 0?this._videoTags[param1].position:this._lastReadPosition;
         var _loc5_:* = 0;
         _log.debug("FlvBlock ReadData startPos:" + _loc4_);
         var _loc6_:* = 0;
         if((this._holder) && (this._holder.runtimeData.playerUseType == PlayerUseTypeEnum.MAIN) && this._holder.runtimeData.playerType == PlayerTypeEnum.MAIN_STATION)
         {
            _loc6_ = Config.STREAM_LONG_BUFFER_TIME;
         }
         else
         {
            _loc6_ = Config.STREAM_NORMAL_BUFFER_TIME;
         }
         var _loc7_:int = _loc3_ + 1;
         var _loc8_:int = this._videoTags.length;
         while(_loc7_ < _loc8_)
         {
            _loc10_ = this._videoTags[_loc7_].time - this._videoTags[_loc3_].time;
            if(_loc10_ > _loc6_ + 2000)
            {
               _loc5_ = this._videoTags[_loc7_].position;
               _log.debug("FlvBlock ReadData endPos:" + _loc5_);
               _loc2_.duration = _loc10_;
               if(param1 == -1)
               {
                  this._lastReadTagIndex = _loc7_;
               }
               break;
            }
            _loc7_++;
         }
         if(_loc5_ == 0)
         {
            _loc5_ = 0;
            _log.debug("FlvBlock ReadData:get to end");
         }
         _bytes.position = _loc4_;
         if(_bytes.bytesAvailable == 0)
         {
            return null;
         }
         _loc2_.bytes = new ByteArray();
         var _loc9_:* = 0;
         if(_loc5_ > 0)
         {
            _loc9_ = _loc5_ - _loc4_;
         }
         if(_loc9_ > _bytes.bytesAvailable || _loc9_ < 0)
         {
            _loc9_ = _bytes.bytesAvailable;
            _log.warn("Invalid bytes length: " + _loc9_ + " startPos: " + _loc4_ + " endPos: " + _loc5_);
         }
         _bytes.readBytes(_loc2_.bytes,0,_loc9_);
         if(param1 == -1)
         {
            this._lastReadPosition = _bytes.position;
            this._eof = _bytes.bytesAvailable == 0 && !this.appending;
         }
         return _loc2_;
      }
      
      public function getData(param1:int) : MediaData {
         var _loc2_:* = -1;
         var _loc3_:* = 0;
         var _loc4_:int = this._videoTags.length;
         while(_loc3_ < _loc4_)
         {
            if(this._videoTags[_loc3_].time > param1)
            {
               if(_loc3_ > 0)
               {
                  _loc2_ = _loc3_ - 1;
               }
               break;
            }
            _loc3_++;
         }
         if(_loc2_ == -1)
         {
            return null;
         }
         var _loc5_:MediaData = this.readData(_loc2_);
         if(_loc5_)
         {
            _loc5_.headers = this.getHeaders();
         }
         return _loc5_;
      }
      
      public function getHeaders() : ByteArray {
         if((this._discard) || this._videoTags.length == 0)
         {
            return null;
         }
         var _loc1_:ByteArray = new ByteArray();
         _loc1_.writeBytes(_bytes,0,this._videoTags[0].position);
         return _loc1_;
      }
      
      public function startAppend() : void {
         if(this._parser)
         {
            throw new Error("the block is started!");
         }
         else
         {
            this._parser = new FLVParser(true);
            _log.info("start appending, startPosition: " + this.startPosition + ", expect end position: " + this._expectEndPosition.toString());
            return;
         }
      }
      
      public function appendBytes(param1:IDataInput) : Boolean {
         var bytes:ByteArray = null;
         var var_31:IDataInput = param1;
         if(var_31.bytesAvailable == 0)
         {
            return true;
         }
         bytes = new ByteArray();
         var_31.readBytes(bytes);
         _bytes.position = _bytes.length;
         try
         {
            this._parser.parse(bytes,true,this.onEachFLVTag);
            if(!this._segment.keyframeInited)
            {
               if((this._metadata) && (this._videoTags.length > 1) && !(this._dataSourceType == DataSourceTypeEnum.ClientP2P))
               {
                  this._segment.setKeyframesByObject(this._metadata.metadata);
               }
            }
         }
         catch(e:Error)
         {
            bytes.position = 0;
            _log.info("FLV Parser Error To Str:" + bytes.readMultiByte(bytes.bytesAvailable,"utf-8"));
            _log.info("FLV Parser Error To Hex:" + bytesToHex(bytes,0,1000));
            return false;
         }
         return true;
      }
      
      private function bytesToHex(param1:ByteArray, param2:uint, param3:uint) : String {
         var i:int = 0;
         var label:uint = 0;
         var var_19:ByteArray = param1;
         var var_32:uint = param2;
         var var_33:uint = param3;
         var str:String = "";
         try
         {
            i = 0;
            while(i < var_33)
            {
               label = var_19[var_32 + i];
               str = str + ((label < 16?"0" + label.toString(16):label.toString(16)) + "-");
               i++;
            }
         }
         catch(name_10:Error)
         {
         }
         return str;
      }
      
      public function endAppend() : void {
         if(this._parser == null)
         {
            return;
         }
         this._parser = null;
         if(this._videoTags.length == 0 || this._videoTags.length == 1 && !this.complete)
         {
            this._discard = true;
         }
         else
         {
            this._discard = false;
         }
         if(this._discard)
         {
            this._endTime = 0;
            this._startTime = -1;
            _bytes = new ByteArray();
            this._videoTags = new Vector.<TagInfo>();
            this._hasMetaData = false;
            this._metadata = null;
            this._configAudioTag = null;
            this._configVideoTag = null;
         }
         _log.info("stop appending. end time: " + this._endTime + " , startPosition: " + this.startPosition + " , endPosition: " + this.endPosition + ", block size: " + _bytes.length);
      }
      
      private function onEachFLVTag(param1:FLVTag) : Boolean {
         var _loc4_:Object = null;
         var _loc5_:Array = null;
         var _loc6_:TagInfo = null;
         if(_bytes.length > this.SIZE_LIMIT)
         {
            if(param1.tagType == FLVTag.TAG_TYPE_VIDEO && FLVTagVideo(param1).frameType == FLVTagVideo.FRAME_TYPE_KEYFRAME)
            {
               this._complete = true;
               _log.info("arrived expect size limit");
               return false;
            }
         }
         var _loc2_:* = _bytes.length == 0;
         if(_loc2_)
         {
            this._parser.getHeader().write(_bytes);
         }
         if(param1.tagType == FLVTag.TAG_TYPE_SCRIPTDATAOBJECT)
         {
            if(this._metadata == null && (_loc2_))
            {
               this._hasMetaData = true;
               this._metadata = param1 as FLVTagScriptDataObject;
            }
            param1.write(_bytes);
            return true;
         }
         if(param1.tagType == FLVTag.TAG_TYPE_AUDIO)
         {
            if(FLVTagAudio(param1).isAACSequenceHeader)
            {
               if(this._configAudioTag == null)
               {
                  this._configAudioTag = param1;
                  param1.write(_bytes);
               }
               return true;
            }
         }
         else if(param1.tagType == FLVTag.TAG_TYPE_VIDEO)
         {
            if(FLVTagVideo(param1).avcPacketType == 0)
            {
               if(this._configVideoTag == null)
               {
                  this._configVideoTag = param1;
                  param1.write(_bytes);
               }
               return true;
            }
         }
         
         var _loc3_:uint = param1.timestamp;
         if(!this._timestampAdjustJudged)
         {
            if(this._segment.index == 0)
            {
               this._timestampNeedAdjust = false;
               this._timestampAdjustJudged = true;
            }
            else if(this._metadata)
            {
               _loc4_ = this._metadata.metadata;
               if(_loc4_)
               {
                  _loc5_ = _loc4_.keyframes.times;
                  if(int(Number(_loc5_[1]) * 1000) == 0)
                  {
                     this._timestampNeedAdjust = true;
                  }
                  else
                  {
                     this._timestampNeedAdjust = false;
                  }
                  this._timestampAdjustJudged = true;
               }
            }
            
         }
         if(this._timestampNeedAdjust)
         {
            _loc3_ = _loc3_ + this._referTimestamp;
            param1.timestamp = _loc3_;
         }
         if(param1.tagType == FLVTag.TAG_TYPE_VIDEO && FLVTagVideo(param1).frameType == FLVTagVideo.FRAME_TYPE_KEYFRAME)
         {
            _loc6_ = new TagInfo();
            _loc6_.keyframe = true;
            _loc6_.position = _bytes.length;
            _loc6_.time = _loc3_;
            this._videoTags.push(_loc6_);
            if(this._startTime == -1)
            {
               this._startTime = _loc3_;
               this._lastReadPosition = _loc6_.position;
               this._lastReadTagIndex = 0;
               this._discard = false;
            }
         }
         if(this._startTime != -1)
         {
            this._endTime = _loc3_;
            this._duration = _loc3_ - this._startTime;
         }
         param1.write(_bytes);
         if(this._expectEndPosition > 0 && this.endPosition >= this._expectEndPosition)
         {
            this._complete = true;
            _log.info("arrived expect end position");
            return false;
         }
         return true;
      }
      
      override public function destroy() : void {
         super.destroy();
         this._videoTags = null;
         this._lastReadTagIndex = -1;
         this._parser = null;
         this._discard = true;
         this._eof = false;
      }
   }
}
